/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Eclipse Foundation - Modified from org.eclipse.jdt.internal.ui.packageview.PackageExplorerProblemTreeViewer
 *******************************************************************************/
package org.schemeway.plugins.schemescript.views;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.packageview.ClassPathContainer;
import org.eclipse.jdt.internal.ui.packageview.IMultiElementTreeContentProvider;
import org.eclipse.jdt.internal.ui.packageview.PackageFragmentRootContainer;
import org.eclipse.jdt.internal.ui.viewsupport.ColoredViewersManager;
import org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;

public  class SchemePackageExplorerProblemTreeViewer extends ProblemTreeViewer {
	// fix for 64372  Projects showing up in Package Explorer twice [package explorer] 
	private List fPendingRefreshes;
	
	public SchemePackageExplorerProblemTreeViewer(Composite parent, int style) {
		super(parent, style);
		fPendingRefreshes= Collections.synchronizedList(new ArrayList());
	}
	public void add(Object parentElement, Object[] childElements) {
		if (fPendingRefreshes.contains(parentElement)) {
			return;
		}
		super.add(parentElement, childElements);
	}
					
	/* (non-Javadoc)
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefresh(java.lang.Object, boolean)
	 */
    protected void internalRefresh(Object element, boolean updateLabels) {
		try {
			fPendingRefreshes.add(element);
			super.internalRefresh(element, updateLabels);
		} finally {
			fPendingRefreshes.remove(element);
		}
	}
    
	protected boolean evaluateExpandableWithFilters(Object parent) {
		if (parent instanceof IJavaProject
				|| parent instanceof ICompilationUnit || parent instanceof IClassFile
				|| parent instanceof ClassPathContainer) {
			return false;
		}
		if (parent instanceof IPackageFragmentRoot && ((IPackageFragmentRoot) parent).isArchive()) {
			return false;
		}
		return true;
	}

	protected boolean isFiltered(Object object, Object parent, ViewerFilter[] filters) {
		if (object instanceof PackageFragmentRootContainer) {
			return !hasFilteredChildren(object);
		}
		
		boolean res= super.isFiltered(object, parent, filters);
		if (res && isEssential(object)) {
			return false;
		}
		return res;
	}
	
	/* Checks if a filtered object in essential (i.e. is a parent that
	 * should not be removed).
	 */ 
	private boolean isEssential(Object object) {
		try {
			if (object instanceof IPackageFragment) {
				IPackageFragment fragment = (IPackageFragment) object;
				if (!fragment.isDefaultPackage() && fragment.hasSubpackages()) {
					return hasFilteredChildren(fragment);
				}
			}
		} catch (JavaModelException e) {
			JavaPlugin.log(e);
		}
		return false;
	}
	
	protected void handleInvalidSelection(ISelection invalidSelection, ISelection newSelection) {
		IStructuredSelection is= (IStructuredSelection)invalidSelection;
		List ns= null;
		if (newSelection instanceof IStructuredSelection) {
			ns= new ArrayList(((IStructuredSelection)newSelection).toList());
		} else {
			ns= new ArrayList();
		}
		boolean changed= false;
		for (Iterator iter= is.iterator(); iter.hasNext();) {
			Object element= iter.next();
			if (element instanceof IJavaProject) {
				IProject project= ((IJavaProject)element).getProject();
				if (!project.isOpen() && project.exists()) {
					ns.add(project);
					changed= true;
				}
			} else if (element instanceof IProject) {
				IProject project= (IProject)element;
				if (project.isOpen()) {
					IJavaProject jProject= JavaCore.create(project);
					if (jProject != null && jProject.exists())
						ns.add(jProject);
						changed= true;
				}
			}
		}
		if (changed) {
			newSelection= new StructuredSelection(ns);
			setSelection(newSelection);
		}
		super.handleInvalidSelection(invalidSelection, newSelection);
	}
	
	/**
	 * {@inheritDoc}
	 */
	protected Object[] addAditionalProblemParents(Object[] elements) {
		//if (showWorkingSets() && elements != null) {
			//return fWorkingSetModel.addWorkingSets(elements);
		//}
		return elements;
	}
	
    //---- special handling to preserve the selection correctly
    private boolean fInPreserveSelection;
    
    
	protected void preservingSelection(final Runnable updateCode) {
		try {
			fInPreserveSelection= true;
			super.preservingSelection(updateCode);
			
		} finally {
			fInPreserveSelection= false;
		}
	}
	
	protected void superSetSelectionToWidget(ISelection selection,  boolean reveal) {
		 super.setSelectionToWidget(selection, reveal);
	}
	
	protected void setSelectionToWidget(final ISelection selection, final boolean reveal) {
		
		Display display = Display.getDefault();
		if (display.isDisposed())
			display = new Display();
		display.asyncExec (new Runnable () {
		      public void run () {
		    	  superSetSelectionToWidget(selection, reveal);
		      }
		   });
	}
	
    private Widget internalFindChild(Widget parent, Object element) {
        Item[] items = getChildren(parent);
        for (int i = 0; i < items.length; i++) {
            Item item = items[i];
            Object data = item.getData();
            if (data != null && equals(data, element))
                return item;
        }
        return null;
    }
	private CustomHashtable createRootAccessedMap(TreePath[] paths) {
		CustomHashtable result= new CustomHashtable(getComparer());
		for (int i= 0; i < paths.length; i++) {
			TreePath path= paths[i];
			Object root= path.getFirstSegment();
			if (root != null) {
				result.put(root, path);
			}
		}
		return result;
	}
	
	public void setSelection(ISelection selection, boolean reveal) {
		
		Control control = getControl();
		if (control == null || control.isDisposed()) {
			return;
		}	
		setSelectionToWidget(selection, reveal);
		updateSelection(selection);
		firePostSelectionChanged(new SelectionChangedEvent(this, selection));
	}
	
}

